Next: 3.13.2 Naked Functions Up: 3.13 Inline Assembler Code Previous: 3.13 Inline Assembler Code Contents Index

##
3.13.1 A Step by Step Introduction

Starting from a small snippet of c-code this example shows for the MCS51 how to use inline assembly, access variables, a function parameter and an array in xdata memory. The example uses an MCS51 here but is easily adapted for other architectures. This is a buffer routine which should be optimized:

> `unsigned char __far __at(0x7f00) buf[0x100];`
> `unsigned char head, tail; /* if interrupts are involved see`
> `section 3.9.1.1 about` `volatile` `*/`
> ``
> `void to_buffer( unsigned char c )`
> `{`
> `if( head != (unsigned char)(tail-1) ) /* cast` `needed` `to avoid promotion to integer */`
> `buf[ head++ ] = c; /* access to a 256 byte aligned array */`
> `}`

If the code snippet (assume it is saved in buffer.c) is compiled with SDCC then a corresponding buffer.asm file is generated. We define a new function `to_buffer_asm()` in file buffer.c in which we cut and paste the generated code, removing unwanted comments and some ':'. Then add ''__asm'' and ''__endasm;''3.6 to the beginning and the end of the function body:

> `/* With a cut and paste from the .asm file, we have something to start with.`
> `The function is not yet OK! (registers aren't saved) */`
> `void to_buffer_asm( unsigned char c )`
> `{`
> `__asm`
> `mov r2,dpl`
> `;buffer.c if( head != (unsigned char)(tail-1) ) /* cast` `needed` `to avoid promotion to integer */`
> `mov a,_tail`
> `dec a`
> `mov r3,a`
> `mov a,_head`
> `cjne a,ar3,00106$`
> `ret`
> `00106$:`
> `;buffer.c buf[ head++ ] = c; /* access to a 256 byte aligned array */`
> `mov r3,_head`
> `inc _head`
> `mov dpl,r3`
> `mov dph,#(_buf >> 8)`
> `mov a,r2`
> `movx @dptr,a`
> `00103$:`
> `ret`
> `__endasm;`
> `}`

The new file buffer.c should compile with only one warning about the unreferenced function argument 'c'. Now we hand-optimize the assembly code and insert an #define USE_ASSEMBLY (1) and finally have:

> `unsigned char __far __at(0x7f00) buf[0x100];`
> `unsigned char head, tail;`
> `#define USE_ASSEMBLY (1)`
> ``
> `#if !USE_ASSEMBLY`
> ``
> `void to_buffer( unsigned char c )`
> `{`
> `if( head != (unsigned char)(tail-1) )`
> `buf[ head++ ] = c;`
> `}`
> ``
> `#else`
> ``
> `void to_buffer( unsigned char c )`
> `{`
> `c; // to avoid warning: unreferenced function argument`
> `__asm`
> `; save used registers here.`
> `; If we were still using r2,r3 we would have to push them here.`
> `; if( head != (unsigned char)(tail-1) )`
> `mov a,_tail`
> `dec a`
> `xrl a,_head`
> `; we could do an ANL a,#0x0f here to use a smaller buffer (see below)`
> `jz t_b_end$`
> `;`
> `; buf[ head++ ] = c;`
> `mov a,dpl ; dpl holds lower byte of function argument`
> `mov dpl,_head ; buf is 0x100 byte aligned so head can be used directly`
> `mov dph,#(_buf>>8)`
> `movx @dptr,a`
> `inc _head`
> `; we could do an ANL _head,#0x0f here to use a smaller buffer (see above)`
> `t_b_end$:`
> `; restore used registers here`
> `_endasm;`
> `}`
> `#endif`

The inline assembler code can contain any valid code understood by the assembler, this includes any assembler directives and comment lines. The assembler does not like some characters like ':' or ''' in comments. You'll find an 100+ pages assembler manual in sdcc/sdas/doc/asxhtm.html or online at `http://sdcc.svn.sourceforge.net/viewvc/*checkout*/sdcc/trunk/sdcc/sdas/doc/asxhtm.html`.

The compiler does not do any validation of the code within the `__asm ... __endasm;` keyword pair. Specifically it will not know which registers are used and thus register pushing/popping has to be done manually.

It is recommended that each assembly instruction (including labels) be placed in a separate line (as the example shows). When the --peep-asm command line option is used, the inline assembler code will be passed through the peephole optimizer. There are only a few (if any) cases where this option makes sense, it might cause some unexpected changes in the inline assembler code. Please go through the peephole optimizer rules defined in file SDCCpeeph.def before using this option.

Next: 3.13.2 Naked Functions Up: 3.13 Inline Assembler Code Previous: 3.13 Inline Assembler Code Contents Index